package com.Algorithm.dynamic;

/**
 * 背包问题
 * (1)  v[i][0]=v[0][j]=0; //表示 填入表 第一行和第一列是0
 * (2) 当w[i]> j 时：v[i][j]=v[i-1][j]   // 当准备加入新增的商品的容量大于 当前背包的容量时，就直接使用上一个单元格的装入策略
 * (3) 当j>=w[i]时： v[i][j]=max{v[i-1][j], v[i]+v[i-1][j-w[i]]}  
 * // 当 准备加入的新增的商品的容量小于等于当前背包的容量,
 * // 装入的方式:
 * v[i-1][j]： 就是上一个单元格的装入的最大值
 * v[i] : 表示当前商品的价值
 * v[i-1][j-w[i]] ： 装入i-1商品，到剩余空间j-w[i]的最大值
 * 当j>=w[i]时： v[i][j]=max{v[i-1][j], v[i]+v[i-1][j-w[i]]} :
 *
 * @author MaoLin Wang
 * @date 2019/11/1514:40
 */
public class KnaspackProblem {
    public static void main(String[] args) {
        int[] w = {1, 4, 3};//物品重量
        int[] val = {1500, 3000, 2000};//物品价值
        int bagCapcity = 4;//背包容量
        int itemNum = val.length;//物品个数

        //为了记录放入商品的情况，定义一个二维数组
        int[][] path = new int[itemNum + 1][bagCapcity + 1];

        //创建二维数组
        int[][] v = new int[itemNum + 1][bagCapcity + 1];


        //初始化第一行和第一列
        for (int i = 0; i < v.length; i++) {
            v[i][0] = 0;//第一列置0

        }
        for (int i = 0; i < v[0].length; i++) {
            v[0][i] = 0;//第一行置0
        }


        //动态规划处理
        for (int i = 1; i < v.length; i++) {//不处理第一行
            for (int j = 1; j < v[0].length; j++) {
                //公式
                if (w[i - 1] > j) {
                    v[i][j] = v[i - 1][j];
                } else {
                    //    v[i][j]=Math.max(v[i-1][j],val[i-1]+v[i-1][j-w[i-1]]);
                    if (v[i - 1][j] < val[i - 1] + v[i - 1][j - w[i - 1]]) {
                        v[i][j] = val[i - 1] + v[i - 1][j - w[i - 1]];
                        //把当前情况记录到path
                        path[i][j] = 1;
                    }else {
                        v[i][j] = v[i - 1][j];
                    }


                }
            }

        }

        //输出v
        for (int i = 0; i < v.length; i++) {
            for (int j = 0; j < v[1].length; j++) {
                System.out.print(v[i][j]+" ");
            }
            System.out.println();
        }

        /*for (int i = 0; i < path.length; i++) {
            for (int j = 0; j < path[i].length; j++) {
                System.out.printf("第%d个商品放入到背包",i);
            }
        }*/

        System.out.println("==============");
        //输出放入的哪些商品
        int i=path.length-1;
        int j=path[0].length-1;
        while (i>0 && j>0){//从path的最后开始找
            if (path[i][j]==1){
                System.out.printf("第%d个商品放入到背包",i);
                j -= w[i-1];
            }
            i--;
        }

    }
}
